iconEuler Home

Iteration and Sequences

This notebooks demonstrates iterations and recursions in EMT.

Our first example is the growth of an amount of money at an interest rate of 5%.

>q=1.05; iterate("x*q",1000,n=10)'
         1000 
         1050 
       1102.5 
      1157.63 
      1215.51 
      1276.28 
       1340.1 
       1407.1 
      1477.46 
      1551.33 
      1628.89 

Let us subtract the amount of 30 in each year, while adding interests, and plot the result for 30 years.

>plot2d(iterate("x*q-30",1000,n=30)):

09 - Iteration

As always in EMT, we could also use a function and call collection to pass additional parameters (or, alternatively, semicolon parameters).

>function addf(x,q,a) := round(x*q+a,2); ...
 iterate({{"addf",1.05,30}},1000,n=6)
[1000,  1080,  1164,  1252.2,  1344.81,  1442.05,  1544.15]

Iterating like this is a simple form of recursion,

09 - Iteration

For more complicate sequences, we use the function "sequence". This function computes the value x[n] from all previous values x[1],...,x[n-1] given in a vector. Additionally the variable n can be used.

Here is an example computing the Fibonacci numbers.

09 - Iteration

>sequence("x[n-1]+x[n-2]",[1,1],10)
[1,  1,  2,  3,  5,  8,  13,  21,  34,  55]

The n-th root of the Fibonacci numbers converges to the golden ratio.

>plot2d(sequence("x[n-1]+x[n-2]",[1,1],500)^(1/(1:500))):

09 - Iteration

Clearly the same can be done with a loop, either inside a function or in a multi-line.

>x=ones(500); for k=3 to 500; x[k]=x[k-1]+x[k-2]; end;

We can compute recursions which depend on all previous elements. In the following example, the n-th element is the sum of all previous elements. This time, we start with a scalar value 1. Of course, the result is 2^n.

>sequence("sum(x)",1,10)
[1,  1,  2,  4,  8,  16,  32,  64,  128,  256]

Instead of an expression in x and n, we can also use a function.

In the following example, we iterate

09 - Iteration

where A is a Matrix, and each x[n] is a 2x1 vector.

>A=[1,1;1,2]; function step(x,n) := A.x[,n-1]
>sequence("step",[1;1],5)
            1             2             5            13            34 
            1             3             8            21            55 

There is the function "matrixpower" which yields the same result. This function is faster, since it uses only log_2(n) matrix multiplications.

>matrixpower(A,4).[1;1]
           34 
           55 

Of course, we could also use a loop in a function, or in the command line.

>x=[1;1]; loop 1 to 4; x=A.x; end; x,
           34 
           55 

The Spiral of Theodorus

As an example, we produce the spiral of Theodorus recursively. The recursion is

09 - Iteration

which produces a series of complex numbers. See

Wikipedia

>function g(n) := 1+I/sqrt(n)

Now we can run the recursion and get a sequence of 17 complex numbers.

>x=sequence("g(n-1)*x[n-1]",1,17); plot2d(x,r=4.2);

We add the connections from 0 to the points in a loop.

>for i=1:cols(x); plot2d([0,x[i]],>add); end; ...
   title("Theodorus Spiral"):

09 - Iteration

If you look at the definition of this curve, you see that you can also use a recursion, which does not use the index n.

And, of course, we do not have to use complex numbers. Instead we use column vectors in the plane.

>function gstep (v) ...
 w=[-v[2];v[1]];
 return v+w/norm(w);
 endfunction

If we iterate 16 times starting from [1;0], we get matrix with the columns containing our vectors.

>x=iterate("gstep",[1;0],16); plot2d(x[1],x[2],r=4.2,>points):

09 - Iteration

Convergence

Often, we want to iterate until convergence. If the function does not converge, the user has to press the escape key to stop the iteration!

>iterate("cos(x)",1)
0.739085133216

If such an iteration converges, the limit is a solution of

09 - Iteration

This examples does also work with interval arithmetic.

>res := iterate("cos(x)",~1,2~)
~0.739085133211,0.7390851332133~

If we make res a little larger, we are able to prove that h contains a fixed point of cos.

>h=expand(res,100), cos(h) << h
~0.73908513309,0.73908513333~
1

Or we could set up a function for the iteration.

>function f(x) := (x+2/x)/2

The iteration x(n+1)=f(x(n)) converges quickly to sqrt(2).

>iterate("f",2)
1.41421356237

It might be easier to use an expression in x instead of a function.

>iterate("(x+2/x)/2",2)
1.41421356237

The function "iterate" with the parameter "n=..." returns the history of 5 iterations.

>iterate("f",2,5)
[2,  1.5,  1.41667,  1.41422,  1.41421,  1.41421]

Starting with an interval does not work.

>niterate("f",~1,2~,5)
[ ~1,2~,  ~1,2~,  ~1,2~,  ~1,2~,  ~1,2~,  ~1,2~ ]

The reason is that the interval arithmetic is too approximate. We can improve the evaluation of the expression using a sub-division of the interval.

>function s(x) := ieval("(x+2/x)/2",x,10)

Then we can iterate until the result is optimal, and the interval does not get smaller. The result is an interval, which must contain a solution of

09 - Iteration

And the only solution of this is

09 - Iteration

>iterate("s",~1,2~)
~1.41421356236,1.41421356239~

The function "iterate" works for vectors too. We try the arithmetic-geometric mean

09 - Iteration

The n-th value is stored in the column vector x[n].

>function g(x) := [(x[1]+x[2])/2;sqrt(x[1]*x[2])]

Using the above function, the iteration converges to the arithmetic geometric mean of the start values.

>iterate("g",[1;2])
      1.45679 
      1.45679 

The convergence is rather quick.

>iterate("g",[1;2],4)
            1           1.5       1.45711       1.45679       1.45679 
            2       1.41421       1.45648       1.45679       1.45679 

Again, we can use an interval iteration. It shows that the iteration is stable. It does not prove, that the limit is in the computed bounds, however.

>iterate("g",[~1~;~2~],4)
Interval 2 x 5 matrix

 ~0.99999999999999978,1.0000000000000002~     ...
  ~1.9999999999999996,2.0000000000000004~     ...

The following iteration converges very slowly.

09 - Iteration

>iterate("sqrt(x)",2,10)
[2,  1.41421,  1.18921,  1.09051,  1.04427,  1.0219,  1.01089,
1.00543,  1.00271,  1.00135,  1.00068]

Applying the accelerator of Steffenson, speeds up the convergence.

>steffenson("sqrt(x)",2,10)
[1.04888,  1.00028,  1,  1]

Iteration on the Command Line

In very simple cases, we can put the iteration into a command line.

>x=2; repeat x=(x+2/x)/2; until x^2~=2; end; x,
1.41421356237

If we want to store all values in a vector, we can use concatenation.

>v=[1]; for i=2 to 8; v=v|(v[i-1]*i); end; v,
[1,  2,  6,  24,  120,  720,  5040,  40320]

Or we can store the results into an existing vector.

>v=ones(1,100); for i=2 to cols(v); v[i]=v[i-1]*i; end; ...
 plot2d(v,logplot=1); textbox("log n!",x=0.5):

09 - Iteration

Remember, that loops have to fit into a single command line even if multi-lines are uses.

>A =[0.5,0.2;0.7,0.1]; b=[2;2]; ...
 x=[1;1]; repeat xnew=A.x-b; until all(xnew~=x); x=xnew; end; ...
 x,
     -7.09677 
     -7.74194 

For such elaborate loops, you should consider EMT programs as shown in the next section.

Iteration in Functions

Of course, the programming language of Euler can also be used to iterate. We give only a few examples here, since the language is described in much detail in a tutorial.

Tutorial about Programs in EMT

For a first example, we define a function to count how long the iteration for the square root takes.

>function map itercount (f$,xstart) ...
 x=xstart;
 count=0;
 repeat
   xnew=f$(x);
   count=count+1;
   until xnew~=x;
   x=xnew;
 end;
 return count;
 endfunction

E.g., we have 5 iterations until the result is good enough, if we start at 2.

>itercount("(x+2/x)/2",2)
5

Since the function vectorizes because of the "map" keyword, we can use it for several start values.

>x=1.5:0.1:10; n=itercount("(x+2/x)/2",x); ...
   plot2d(x,n):

09 - Iteration

Using the matrix language, we extract the values, where the iteration count increases.

>x[nonzeros(differences(n))]
[1.5,  2,  3.4,  6.6]

For a second example, we iterate the Newton method of a complex polynomial 10 times for an array of complex numbers.

>p &= x^3-1; expr &= x-p/diff(p,x)
                                   3
                                  x  - 1
                              x - ------
                                      2
                                   3 x

We need a function, which does the iteration 10 times.

>function itertest (f$,x,n=10) ...
 loop 1 to n; x=f$(x); end;
 return x;
 endfunction

Now we can start in a grid of complex values.

>r=1.2; x=linspace(-r,r,501); Z=x+I*x'; W=itertest(expr,Z);

Here are the zeros of this equation.

>z=&solve(p)()
[ -0.5+0.866025i,  -0.5-0.866025i,  1+0i  ]

To plot, we measure the distance between the 10-th iteration and each of the zeros, and use this to compute a color plot, which shows the limit point for each starting point.

The function plotrgb() uses the current plot window to plot the RGB values as a matrix.

>C=rgb(max(abs(W-z[1]),1),max(abs(W-z[2]),1),max(abs(W-z[3]),1)); ...
   plot2d(none,-r,r,-r,r); plotrgb(C):

09 - Iteration

Symbolic Iteration

To generate a vector of symbolic values in Maxima, there is the function makelist().

>vexpr &= makelist(taylor(exp(x),x,0,k),k,1,3)
                          2           3    2
                         x           x    x
                 [x + 1, -- + x + 1, -- + -- + x + 1]
                         2           6    2

To transfer this to a vector of strings in EMT, use mxm2str(). You can then plot this vector of expressions in EMT.

>plot2d("exp(x)",0,3); plot2d(mxm2str("vexpr"),>add,color=4:6):

09 - Iteration

Of course, you could also extract a single string easily. Then, e.g., plot these expressions in a loop.

>&vexpr[3]
                            3    2
                           x    x
                           -- + -- + x + 1
                           6    2

Maxima does also have a sum() function, which can be used to generate series.

>&sum(sin(k*x)/k,k,1,5)
          sin(5 x)   sin(4 x)   sin(3 x)   sin(2 x)
          -------- + -------- + -------- + -------- + sin(x)
             5          4          3          2

Let us plot

09 - Iteration

>plot2d(&sum(sin((2*k+1)*x)/(2*k+1),k,0,20),0,2pi):

09 - Iteration

To achieve the same numerically would not be difficult. Here is an example. We use the matrix language to generate a matrix with

09 - Iteration

Then we sum over the rows to get the values of the function at each x[i].

>x=linspace(0,2pi,1000); k=1:100; y=sum(sin(k*x')/k)'; ...
 plot2d(x,y):

09 - Iteration

Tables of Functions

There is an interesting way to generate a sequence using Maxima expressions. The mxmtable() command will by default print and plot the sequence, and it returns the sequence as a column vector.

For an example we generate the n-th derivatives of x^x at 1.

>mxmtable("diffat(x^x,x=1,n)","n",1,8,frac=1);
        1 
        2 
        3 
        8 
       10 
       54 
      -42 
      944 

09 - Iteration

Euler Home